package com.hps.demo.consumer;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author hps
 * @Description:
 * @Date Created in 18:53 2019/7/11
 */
public class RpcClient {

    private static CuratorFramework client = null;

    private static Map<String, List<String>> serviceMap = new ConcurrentHashMap<>();

    static {
        client = CuratorFrameworkFactory.builder()
                .connectString("192.168.26.143:2181")
                .namespace("registry")
                .connectionTimeoutMs(2000)
                .retryPolicy(new ExponentialBackoffRetry(1000, 3))
                .build();
        client.start();
    }

    @SuppressWarnings("unchecked")
    public static <T> T getService(Class<T> clazz) {
        String clazzName = clazz.getName();
        String path = "/" + clazzName;
        try {
            if (serviceMap.get(clazzName) == null) {
                List<String> servicePath = client.getChildren().forPath(path);
                if (!CollectionUtils.isEmpty(servicePath)) {
                    serviceMap.put(clazzName, servicePath);
                }

                registryWatch(clazzName, path);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, new RpcHandler(serviceMap));
    }

    private static void registryWatch(final String className, final String path) throws Exception {
        PathChildrenCache nodeCache=new PathChildrenCache(client,path,true);
        PathChildrenCacheListener nodeCacheListener= (curatorFramework1, pathChildrenCacheEvent) -> {
            List<String> servicePath = client.getChildren().forPath(path);
            if (CollectionUtils.isEmpty(servicePath)) {
                serviceMap.remove(className);
            } else {
                serviceMap.put(className, servicePath);
            }
        };
        nodeCache.getListenable().addListener(nodeCacheListener);
        nodeCache.start();
    }
}
